package blue.global.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import blue.system.model.Role;
import blue.system.model.User;

/**
 * 反射工具类
 * 
 * @author zhengj
 * @since 2009-3-2 1.0
 */
public class ReflectionUtil
{
	private ReflectionUtil()
	{
	}

	/**
	 * 根据类的一个属性取得它对应的 Setter 方法
	 * 
	 * @param clazz 类的类型
	 * @param field 类的一个属性
	 * @return 对应的 Setter 方法
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	public static Method getSetterMethod(Class<?> clazz, Field field)
			throws SecurityException, NoSuchMethodException
	{
		return getMethod("set", clazz, field);
	}

	/**
	 * 根据类的一个属性取得它对应的 Getter 方法
	 * 
	 * @param clazz 类的类型
	 * @param field 类的一个属性
	 * @return 对应的 Getter 方法
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	public static Method getGetterMethod(Class<?> clazz, Field field)
			throws SecurityException, NoSuchMethodException
	{
		Method method = getMethod("get", clazz, field);
		if (method == null)
			method = getMethod("is", clazz, field);
		return method;
	}

	/**
	 * 根据类的一个属性取得它对应的方法
	 * 
	 * @param type Setter/Getter方法
	 * @param clazz 类的类型
	 * @param field 类的一个属性
	 * @return 对应的方法
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	private static Method getMethod(String type, Class<?> clazz, Field field)
			throws SecurityException, NoSuchMethodException
	{
		String fieldName = field.getName();
		String starter = fieldName.substring(0, 1).toUpperCase();
		String methodName = type + starter + fieldName.substring(1);
		Method method = null;
		if (type.equals("set"))
			method = clazz.getDeclaredMethod(methodName, field.getType());
		else if (type.equals("get") || type.equals("is"))
			method = clazz.getDeclaredMethod(methodName);
		return method;
	}

	/**
	 * <p>
	 * 用 XML 序列化对象
	 * </p>
	 * 
	 * @param obj 对象
	 * @return 序列化字符串，如果 obj 为 null，则返回 null
	 */
	public static String serialize(Object obj)
	{
		if (obj == null)
			return null;

		StringBuilder xml = new StringBuilder();
		List<Object> repeatList = new ArrayList<Object>();
		serialize(xml, obj, null, 1, repeatList);
		
		return xml.toString();
	}
	
	private static void serialize(StringBuilder xml, Object obj, String name, int deepth, List<Object> repeatList)
	{
		final String start = "<%s class=\"%s\">\n";
		final String end = "</%s>\n";
		final String prefix = "\t";
		
		for (Object repeat : repeatList)
		{
			if (repeat == obj)
				return;
		}
		repeatList.add(obj);
		
		Class<?> clazz = obj.getClass();
		if (name == null || name.equals(""))
		{
			xml.append(String.format(start, "object", clazz.getName()));
		}
		else
		{
			xml.append(String.format(start, name, clazz.getName()));
		}
		
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields)
		{
			try
			{
				Method getter = getGetterMethod(clazz, field);
				for (int i = 0; i < deepth; i++)
				{
					xml.append(prefix);
				}
				Object value = getter.invoke(obj);
				String fieldName = field.getName();
				
				if (value.getClass().isPrimitive()
						|| value instanceof CharSequence
						|| value instanceof Number
						|| value instanceof Date)
				{
					xml.append(String.format(start, fieldName, value.getClass().getName()));
					for (int i = 0; i < deepth + 1; i++)
					{
						xml.append(prefix);
					}
					
					if (value instanceof Date)
					{
						xml.append(DateUtil.toDateTimeString((Date)value)).append("\n");
					}
					else
					{
						xml.append(value).append("\n");
					}
				
					for (int i = 0; i < deepth; i++)
					{
						xml.append(prefix);
					}
					xml.append(String.format(end, field.getName()));
					
				}
				else
				{
					serialize(xml, value, fieldName, deepth + 1, repeatList);
				}
			}
			catch (Exception e)
			{
			}
		}
		if (name == null || name.equals(""))
		{
			xml.append(String.format(end, "object"));
		}
		else
		{
			xml.append(String.format(end, name));
		}
	}
	
	
	public static void main(String[] args)
	{
		Role role = new Role();
		role.setId(UUID.generator());
		role.setName("admin");
		User user = new User();
		user.setId(UUID.generator());
		user.setName("blue");
		user.setPassword("password");
		user.setRole(role);
		
		System.out.println(serialize(user));
	}
}
